import socket
import gzip
from StringIO import StringIO
import select

class HTTPClient:
  _http_vsn_str = 'HTTP/1.1'
  recv_buffer = 40960
  default_port = 80

  def __init__(self, url=None):        
    if not url:
      print 'Error URL!'
    if url.find('.com')==-1 and url.find('.cn')==-1\
      and url.find('edu'):
      print 'Error URL! Please input the Right URL,thx!'
    print self._get_hostport(url), '\n'
    self._recv_buff = ''
    #self._get_hostport(url)  
  
  def __del__(self):
    self._close()

  def _get_hostport(self, url):
    if url.find('http://') == 0:
      self.__hostport = url[7: url[8:].find('/') + 8]
      self.resource = url[7+len(self.__hostport):]
    elif url.find('https://') == 0:
      self.__hostport = url[8: url[8:].find('/') + 8]
      self.resource = url[8+len(self.__hostport):]
    elif url.find('/') == -1:
      self.__hostport = url
      self.resource = '/'
    else:
      self.__hostport = url[:url.find('/')]
      self.resource = url[len(self.__hostport):]
 
    i = self.__hostport.rfind(':')
    if i > 0:
      self.host = self.__hostport[:i]
      self.port = int(self.__hostport[i+1:])
    else:
      self.host = self.__hostport
      self.port = self.default_port

    self.ip = self._get_ip(self.host)

    return (self.ip, self.port, self.resource) 
       
  '''
      j = self.__hostport.rfind(']')         # ipv6 addresses have [...]
      if i > j:
          try:
              port = int(self.__hostport[i+1:])
          except ValueError:
              if self.__hostport[i+1:] == "":  # http://foo.com:/ == http://foo.com/
                  self.port = self.default_port
              else:
                 # raise InvalidURL("nonnumeric port: '%s'" % host[i+1:])
          self.host = self.__hostport[:i]
      else:
          self.port = self.default_port
      if self.__hostport and self.__hostport[0] == '[' and self.__hostport[-1] == ']':
          host = self.__hostport[1:-1]
      return (self.host, self.port)
  '''
      
  def _get_ip(self, host):
    return socket.getaddrinfo(host,'http')[0][4][0]
    
  def _connect(self):
    self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM);
    try:
       self.sock.connect((self.ip, self.port))
    except Exception, e:
      print str(e)

  def _send(self, message):
     self.sock.send(message);

  def _receive(self):
     self._recv_buff = self.sock.recv(self.recv_buffer)
 
  # Receive information with select network API.   
  def _receive_select(self):
    rlist = [self.sock]
    __running = 1
    __start = 1
    self._message_len = -1
    self._trans_encode_type = ''
    self._received_len = 0
    while __running:
      try:
        rs,ws,es = select.select(rlist, [], [], 10)
      except Exception, e:
        print str(e)
      for s in rs:
        if s is self.sock:
          __buf_tmp = s.recv(self.recv_buffer)
          if __start:
            __index_transfer_coding_start = int(__buf_tmp.find('Transfer-Encoding: '))
            if __index_transfer_coding_start > 0:
              __index_transfer_coding_start += len('Transfer-Encoding: ') 
              __index_transfer_coding_end = __buf_tmp.find('\r\n', __index_transfer_coding_start)
              self._trans_encode_type = __buf_tmp[__index_transfer_coding_start:__index_transfer_coding_end]
              __start = 0
              self._recv_buff += __buf_tmp  #Buffer the firs chunk.
              continue
            
            else:
              __index_content_len_start = __buf_tmp.find('Content-Length:')
              if __index_content_len_start > 0:
                __index_content_len_start += len('Content-Length:') + 1         
                __index_content_len_end = __buf_tmp.find('\r\n', __index_content_len_start)
                self._message_len = int(__buf_tmp[__index_content_len_start:__index_content_len_end])
                __start = 0
          
          #Buffer the rest of chunks.
          if self._trans_encode_type  == 'chunked':
            __chunk_size_end = __buf_tmp.find('\r\n')
            print __chunk_size_end
            print __buf_tmp[:__chunk_size_end]
            print __buf_tmp
            __running = 0
            __chunk_size = int(__buf_tmp[:__chunk_size_end], 16)
            print __chunk_size
            if __chunk_size == 0:
              __running = 0
              continue
            self._recv_buff += __buf_tmp[__chunk_size_end+2:-2]
          
          elif self._message_len > 0:
            self._received_len += len(__buf_tmp)
            self._recv_buff += __buf_tmp

            if self._received_len == self._message_len:
              __running = 0
          
          else:
            print 'There is no both Content-Length field and Tranfer-Encoding'
            __running = 0

  def _close(self):
    self.sock.close()

  def request(self, method='GET'):
    self._connect()
    if method == 'GET':
	  send_message = self._put_get_header(method)
	  self.sock.send(send_message)
    #self._receive()
    self._receive_select()
       
  def get_all_response(self):
    self.get_header_response()
    self._recv_body = self._recv_buff[self._header_end + 4:]
    print len(self._recv_body)
  ''' 
    print self._recv_body
    
    if self._recv_header.find('gzip') > 0:
      self._decompress(self._recv_body)
      print self._recv_header
      print self._outdata_decompress
    else:
      print self._recv_header
      print self._recv_body     
  '''
  def get_header_response(self):
    self._header_end = self._recv_buff.find('\r\n\r\n')
    self._recv_header = self._recv_buff[:self._header_end];
    print 'The HTTP packet of response of GET Request:'
    print self._recv_header, '\n'

  def _put_get_header(self, method='GET'):
    return self._construct_content(method, self.resource, self.host)
        
        
  def _construct_content(self, method='GET', resource='/', host='www.uc.cn'):
    header = '%s %s %s' % ('GET', resource, 'HTTP/1.1\r\n');
    Host = '%s\r\n' % (host);
    Connection = 'keep-alive\r\n';
    Cache_Control = 'max-age=0\r\n';
    Accept = 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\r\n';
    User_Agent = 'Mozilla/5.0 (windows NT 6.1; WOW64) Applewekbit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 safari/537.36\r\n';
    DNT = '1\r\n';
    Accept_Encoding = 'gzip,deflate,sdch\r\n';
    Accept_Language = 'zh-CN,zh;q=0.8,en;q=0.6,zh-TW;q=0.4,fr;q=0.2\r\n';
    Cookie = 'jomie\r\n';
    #If_Modified_Since = 'Thu, 03, Jul 2014 11:50:55 GMT\r\n';

    #get_content = '%sHost:%sConnection:%sCache-Control:%sAccept:%sUser-Agent:%sDNT:%sAccept-Encoding:%sAccept-Language:%sCookie:%sIf-Modified-Since:%s' %\
    #             (header, Host, Connection, Cache_Control, Accept, User_Agent, DNT, Accept_Encoding, Accept_Language, Cookie,If_Modified_Since);

    get_content = '%sHost: %sConnection: %sCache-Control: %sAccept: %sUser-Agent: %sDNT: %sAccept-Encoding: %sAccept_Language: %sCookie: %s\r\n' %\
                  (header, Host, Connection, Cache_Control, Accept, User_Agent, DNT, Accept_Encoding, Accept_Language, Cookie);
    return get_content;
  
  def _decompress(self, datagzip):
    print '_decompress func==========================='
    try:
      __buf = StringIO(datagzip)
      __of = gzip.GzipFile(fileobj=__buf)
      self._outdata_decompress = __of.read()
    except Exception, e:
      print str(e)
      
  def un_zip(self, data):
    try:
      print 'unzip======================'
      compressedstream = StringIO(data)
      gziper = gzip.GzipFile(fileobj=compressedstream)
      return gziper.read()
    except Exception, e:
      print str(e)

  def putheader(self, header, *values):
    """Send a request header line to the server.

      For example: h.putheader('Accept', 'text/html')
      """
    hdr = '%s: %s' % (header, '\r\n\t'.join([str(v) for v in values]))
    self._output(hdr)

  def putrequest(self, method, resouce, skip_host=0, skip_accept_encoding=0):

    hdr = '%s %s %s' % (method, url, self._http_vsn_str)

    self._output(hdr)

    if self._http_vsn == 11:

      if not skip_host:
        netloc = ''
        if url.startswith('http'):
          nil, netloc, nil, nil, nil = urlsplit(url)

        if netloc:
          try:
              netloc_enc = netloc.encode("ascii")
          except UnicodeEncodeError:
              netloc_enc = netloc.encode("idna")
          self.putheader('Host', netloc_enc)
        else:
          if self._tunnel_host:
            host = self._tunnel_host
            port = self._tunnel_port
          else:
            host = self.host
            port = self.port

          try:
            host_enc = host.encode("ascii")
          except UnicodeEncodeError:
            host_enc = host.encode("idna")
          # Wrap the IPv6 Host Header with [] (RFC 2732)
          if host_enc.find(':') >= 0:
            host_enc = "[" + host_enc + "]"
          if port == self.default_port:
            self.putheader('Host', host_enc)
          else:
            self.putheader('Host', "%s:%s" % (host_enc, port))

 
      if not skip_accept_encoding:
        self.putheader('Accept-Encoding', 'identity')
    else:
       pass



  def _output(self, s):
    """Add a line of output to the current request buffer.

    Assumes that the line does *not* end with \\r\\n.
    """
    self._buffer.append(s)

  def _get_header_information(self, response_message):
    pass
